﻿<cfsilent>
	<cfscript>
		
		jsonAdvice = getProperty("serviceFactory").getBean("jsonAdvice");
		mathAdvice = getProperty("serviceFactory").getBean("senateMathAdvice");
		
		sequenceStudentExamResit = getProperty("serviceFactory").getBean("sequenceStudentExamResit");
		sequenceClassroomTimeTable = getProperty("serviceFactory").getBean("sequenceClassroomTimeTable");
		
		response = structNew();
		structInsert(response, "success", false, true);

		progress = [];
		rooms = [];
		
		examId = event.getArg("EXID");
		roomIds = event.getArg("RoomIDs");
		
		transaction {
			
			/* 加载考试任务 */
			
			sql = "SELECT a.task_prog,
						   a.rstidx,
						   a.cid,
						   b.course_name,
						   a.wid,
						   a.wdidx,
						   a.cellidx,
						   a.campus_id,
						   a.term_id
				FROM t_resittask a 
					 INNER JOIN t_course b ON b.cid = a.cid 
				WHERE a.task_exrstid = :examId ";
				
			queryObj = new Query( datasource=application.dnsMaster ) ;
			queryObj.addParam( name="examId", value=examId, cfsqltype="cf_sql_char" );
			
			rs_examTask= queryObj.execute( sql=sql ).getResult();
			
			arrayAppend( progress, "检查考试安排状态" );
			
			if ( rs_examTask.task_prog eq "1" ) {
					
				
					usage = "3";

					term = rs_examTask.term_id;
					termId = rs_examTask.term_id;
					examIdx = rs_examTask.rstidx;
					courseId = rs_examTask.cid;
					courseName = rs_examTask.course_name;

					/* 获取考试的教学班列表 */
						
					sql = "SELECT 
							a.task_id 
							FROM t_resitplan a  
							WHERE 
								a.cid = :courseId 
								AND 
								a.term_id = :termId 
								AND 
								a.rstidx = :examIdx ";
								
					queryObj = new Query( datasource=application.dnsMaster ) ;
					queryObj.addParam( name="courseId", value=courseId, cfsqltype="cf_sql_varchar" );
					queryObj.addParam( name="termId", value=termId, cfsqltype="cf_sql_char" );
					queryObj.addParam( name="examIdx", value=examIdx, cfsqltype="cf_sql_char" );
					
					rs_taskIds= queryObj.execute( sql=sql ).getResult();
					
		
					/* 需参加补考的学生 */
		
					sql = "SELECT 
							a.stu_id, a.scc_id
							FROM t_temp_mark_resit a  
							WHERE 
								a.task_id IN (:taskIds ) 
							ORDER BY a.task_id";
					
					
					queryObj = new Query( datasource=application.dnsMaster ) ;
					queryObj.addParam( name="taskIds", value=arrayToList(rs_taskIds["task_id"],"|"), cfsqltype="cf_sql_varchar",list = true,separator="|" );
					
					rs_student= queryObj.execute( sql=sql ).getResult();
						
					/* 随机编排学生 进行1/3乱序交换 */
					
		
					studentCount = rs_student.recordCount;
					
					arrayAppend( progress, "课程补考人数为 " & studentCount & "人" );
					
					/* 刷新考试人数 */
					
					examWeek = int(rs_examTask.wid);
					examWeekDay = rs_examTask.wdidx;
					examCell = rs_examTask.cellidx;
					campusId = rs_examTask.campus_id;	
					
					examWeekIdx = mathAdvice.convertExamWeekIdx(examWeek);
					
					/* 进行开学前学期修正 */
					if ( examWeek eq -1 ) { examWeek = 25; }
					
					cells = 2;
					/* 如果为 第二讲 或 第五讲 则使用最长学时数 */
					if (examCell eq 2 or examCell eq 5) { cells = 3; }
					
					cellStart = mathAdvice.convertLectureIdxToCellStart(examCell);
					cellEnd = cellStart + cells -1;
					
					/* 根据已选教室 教学楼和楼层进行排序 */
			
					sql = "SELECT 
							a.cr_id, 
							a.classroom, 
							a.sits_exam
							FROM t_classroom a 
							WHERE 
								a.cr_id IN ( :roomIds ) 
								AND 
								SUBSTR(a.cr_usage, 3, 1) = '1' 
								AND 
								a.campus_id = :campusId 
								AND  
								NOT EXISTS (
									SELECT 1 
									FROM t_clsroom_timetable b
									WHERE 
										a.cr_id = b.cr_id
										AND 
										b.term_id = :termId 
										AND 
										b.wdidx = :weekDay 
										AND
										NOT ( b.cellidx + b.cellrelay -1 < :cellStart or b.cellidx > :cellEnd) 
										AND 
										SUBSTR(b.widx, #int(examWeek)#, 1) = '1' 
								) 
							ORDER BY a.b_id, a.cr_floor, a.classroom";	
							
					queryObj = new Query( datasource=application.dnsMaster ) ;
					queryObj.addParam( name="roomIds", value=roomIds, cfsqltype="cf_sql_char",list=true, separator="|");
					queryObj.addParam( name="termId", value=termId, cfsqltype="cf_sql_char" );
					queryObj.addParam( name="weekDay", value=examWeekDay, cfsqltype="cf_sql_char" );
					queryObj.addParam( name="cellStart", value=cellStart, cfsqltype="cf_sql_integer" );
					queryObj.addParam( name="cellEnd", value=cellEnd, cfsqltype="cf_sql_integer" );
					queryObj.addParam( name="campusId", value=campusId, cfsqltype="cf_sql_char" );
					
					rs_clsroom= queryObj.execute( sql=sql ).getResult();	
					
					
					sitsCount = 0;
						
					for ( a=1; a LTE rs_clsroom.recordCount; a++) {
						sitsCount = sitsCount + rs_clsroom["sits_exam"][a];
					}
					
					arrayAppend( progress, "已选教室" & rs_clsroom.recordCount & "个, 考场最高容量" & sitsCount & "座" );
					
					
					if ( sitsCount gte studentCount ) {
						
						/* 教室足够 */
						/* 开始平均分布考场和人数 */
						
						clsroomToArrange = [];
						sitsUsed = 0;
						
						for ( b=1; b LTE rs_clsroom.recordCount; b++) {
									
							sitsUsed = sitsUsed + rs_clsroom["sits_exam"][b];
									
							arrayAppend(clsroomToArrange, [ rs_clsroom["cr_id"][b], rs_clsroom["classroom"][b], rs_clsroom["sits_exam"][b], 0 ] );
							
							if ( sitsUsed gte studentCount ) {
								break;
							}
						}
						
						roomCount = arrayLen(clsroomToArrange);
								
						/* 平均分配学生座次 */
						studentAvgPerRoom = int( studentCount / roomCount );
						studentLeft = studentCount;
								
						/* 先按照平均数分配人数 */
						for ( i=1; i lte roomCount; i++ ) {
									
							if ( clsroomToArrange[i][3] gte studentAvgPerRoom ) {
								clsroomToArrange[i][4] = studentAvgPerRoom;
								studentLeft = studentLeft - studentAvgPerRoom;
							}
							else {
								clsroomToArrange[i][4] = clsroomToArrange[i][3];
								studentLeft = studentLeft - clsroomToArrange[i][3];
							}
									
						}
															
						/* 再平均分配剩余人数 */
						while ( studentLeft gt 0 ) {
									
									
							for ( i=1; i lte roomCount; i++ ) {
									
								if ( studentLeft eq 0) {
									break;
								}
										
								if ( clsroomToArrange[i][4] lt clsroomToArrange[i][3] ) {
									clsroomToArrange[i][4] ++;
									studentLeft --;
								}
										
							}
									
						}
						
						arrayAppend( progress, "平均分布考场学生到" & roomCount & "个考场" );
						
						studentStart = 0;
						studentEnd = 0;
						
						for ( clsroomTarget in clsroomToArrange ) {
									
							/* 标注该考场已用于考试 */
							classRoom = clsroomTarget[1];
							
							sql = "SELECT a.sits_exam,
										   a.cr_id,
										   a.classroom
									FROM t_classroom a 
									WHERE a.cr_id = :clsroomId ";
												
							queryObj = new Query( datasource=application.dnsMaster ) ;
							queryObj.addParam( name="clsroomId", value=classRoom, cfsqltype="cf_sql_char");
							
							rs_classRoom= queryObj.execute( sql=sql ).getResult();
					
							
							sequenceClassroomTimeTable.setTermID(termId);
							sequenceClassroomTimeTable.setClassroomID(classRoom);
							
							useIdx = sequenceClassroomTimeTable.getIDX();
							
							sequenceClassroomTimeTable.setIndex(useIdx);
									
							useId = sequenceClassroomTimeTable.getID();	
							
							ClassRoomTimeID=useId;
							UseIndex=useIdx;
							TaskResitExamID=examId; 
							ExamCourses=courseName;
							CourseCount=1;
							SitUsed=clsroomTarget[4];
							SitLeft=rs_classRoom.sits_exam-clsroomTarget[4];
							WeekIndex=mathAdvice.convertExamWeekIdx(examWeek);
							WeekDay=examWeekDay;
							CellStart=cellStart;
							CellLength=cells;
							Term=termId;
							ClassRoom=classRoom;
							Usage=usage;
							
							
							sql = "INSERT INTO t_clsroom_timetable (
													   crtime_id,
													   uidx,
													   widx,
													   wdidx,
													   cellidx,
													   cellrelay,
													   term_id,
													   cr_id,
													   ut_id
												) VALUES (
														:ClassRoomTimeID ,
														:UseIndex ,
														:WeekIndex ,																							                                                    :WeekDay ,																														                                                    :CellStart ,																														                                                    :CellLength ,																															                                                    :Term ,																																                                                    :ClassRoom ,																												                                                    :Usage 
												)";
												
								queryObj = new Query( datasource=application.dnsMaster) ;
								queryObj.addParam( name="ClassRoomTimeID", value=ClassRoomTimeID, cfsqltype="cf_sql_char" );
								queryObj.addParam( name="UseIndex", value=UseIndex, cfsqltype="cf_sql_char" );
								queryObj.addParam( name="WeekIndex", value=WeekIndex, cfsqltype="cf_sql_char" );
								queryObj.addParam( name="WeekDay", value=WeekDay, cfsqltype="cf_sql_char" );
								queryObj.addParam( name="CellStart", value=CellStart, cfsqltype="cf_sql_integer" );
								queryObj.addParam( name="CellLength", value=CellLength, cfsqltype="cf_sql_integer" );
								queryObj.addParam( name="Term", value=Term, cfsqltype="cf_sql_char" );
								queryObj.addParam( name="ClassRoom", value=ClassRoom, cfsqltype="cf_sql_char" );
								queryObj.addParam( name="Usage", value=Usage, cfsqltype="cf_sql_char" );
								queryObj.execute( sql=sql );
								
								sql = "INSERT INTO t_clsroom_forresit (
											   crtime_id,
											   task_exrstid,
											   exam_courses,
											   course_count,
											   sits_used,
											   sits_left
										) VALUES (
												:ClassRoomTimeID ,
												:TaskResitExamID , 																									        									:ExamCourses ,																												                                    		:CourseCount ,																																                                    		:SitUsed ,																															                                   		 	:SitLeft 		
										)";
										
								queryObj = new Query( datasource=application.dnsMaster) ;
								queryObj.addParam( name="ClassRoomTimeID", value=ClassRoomTimeID, cfsqltype="cf_sql_char" );
								queryObj.addParam( name="TaskResitExamID", value=TaskResitExamID, cfsqltype="cf_sql_char" );
								queryObj.addParam( name="ExamCourses", value=ExamCourses, cfsqltype="cf_sql_varchar" );
								queryObj.addParam( name="CourseCount", value=CourseCount, cfsqltype="cf_sql_integer" );
								queryObj.addParam( name="SitUsed", value=SitUsed, cfsqltype="cf_sql_integer" );
								queryObj.addParam( name="SitLeft", value=SitLeft, cfsqltype="cf_sql_integer" );
								queryObj.execute( sql=sql );
							
							/* 依次编排学生座位及考场 */
							sitidx = 0;
									
							studentStart = studentEnd + 1;
							studentEnd = studentEnd + clsroomTarget[4];
									
							for ( i=studentStart; i lte studentEnd; i++ ) {
										
								sitidx++;
								student = rs_student["stu_id"][i];
						
								
								sequenceStudentExamResit.setTaskResitExamID(examId);
								sequenceStudentExamResit.setStudentID(student);
								stuExamId = sequenceStudentExamResit.getID();
								
								ExamerID= stuExamId ;				
								SitIndex=sitidx;
								ChooseID=rs_student["scc_id"][i]; 
								Student=student;
								ExamResitTask=examId;
								Classroom=classRoom ;
								
								
								sql = "INSERT INTO t_student_resit(
													scrsex_id, 
													sitidx, 
													scc_id, 
													stu_id, 
													task_exrstid, 
													cr_id 
												)VALUES(
													:ExamerID ,
													:SitIndex ,
													:ChooseID ,
													:Student ,
													:examId ,
													:Classroom 
												)";
								
									queryObj = new query( datasource=application.dnsMaster );
									queryObj.addParam( name="ExamerID", value=ExamerID, cfsqltype="cf_sql_varchar" ); 
									queryObj.addParam( name="SitIndex", value=SitIndex, cfsqltype="cf_sql_integer" );
									queryObj.addParam( name="ChooseID", value=ChooseID, cfsqltype="cf_sql_varchar" );
									queryObj.addParam( name="Student", value=Student, cfsqltype="cf_sql_varchar" );
									queryObj.addParam( name="examId", value=examId, cfsqltype="cf_sql_char" );
									queryObj.addParam( name="Classroom", value=Classroom, cfsqltype="cf_sql_char" );
									queryObj.execute( sql=sql );
										
							}
									
							arrayAppend( rooms, [rs_classRoom.classroom,rs_classRoom.sits_exam, clsroomTarget[4], studentStart, studentEnd ] );
	
									
						}
								
						/* 更新考试状态为已安排场地 */
				
						ExamSize = studentCount ;
						TaskProgress = "2" ;
						
						sql = "UPDATE t_resittask 
								SET examer_sum = :examSize, 
									task_prog = :taskProg 
							WHERE task_exrstid = :taskExamId ";
		 
						queryObj = new query( datasource=application.dnsMaster ); 
						queryObj.addParam( name="examSize", value=studentCount, cfsqltype="cf_sql_integer" ); 
						queryObj.addParam( name="taskProg", value="2", cfsqltype="cf_sql_char" ); 
						queryObj.addParam( name="taskExamId", value=examId, cfsqltype="cf_sql_char" ); 
						queryObj.execute( sql=sql );
								
						arrayAppend( progress, "编排学生座次完成" );
								
						structInsert(response, "success", true, true);
						
						
					}
					else {
						/* 考场不足 */
						structInsert(response, "reason", "当前考试时间没有足够的考场", true);
					}
					
				}
				else {
					
					structInsert(response, "ExamID", examId, true);
					structInsert(response, "reason", "考试状态异常 标注为等待安排场地状态", true);
					
				}
				
			}
			
			structInsert(response, "Progress", progress, true);
			structInsert(response, "ClassRoom", rooms, true);
			
	</cfscript>
</cfsilent><cfoutput>#jsonAdvice.encode(data:response, stringNumbers:true)#</cfoutput>